package com.foreveross.project.usercenterserver.security.config;

import com.foreveross.project.usercenterserver.common.constant.RoleEnum;
import com.foreveross.project.usercenterserver.security.handler.CustomAccessDeniedHandler;
import com.foreveross.project.usercenterserver.security.handler.CustomAuthenticationFailureHandler;
import com.foreveross.project.usercenterserver.security.handler.CustomAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

import javax.servlet.http.HttpServletRequest;

/**
 * @author: yz
 * @Date: 2019/7/17 11:13 AM
 */
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Autowired
    CustomAccessDeniedHandler customAccessDeniedHandler;

    //认证过滤器中使用
    //在登录验证时，附带增加额外的数据，如验证码、用户类型等
    //该类提供了获取用户登录时携带的额外信息的功能，默认实现WebAuthenticationDetails提供了remoteAddress与sessionId信息。开发者可以通过Authentication的getDetails()获取WebAuthenticationDetails
    @Autowired
    AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;



    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 忽略拦截前端资源
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) {
        web
                .ignoring()
                .antMatchers(
                        "swagger-ui.html",
                        "**/swagger-ui.html",
                        "/favicon.ico",
                        "/**/*.css",
                        "/**/*.js",
                        "/**/*.png",
                        "/**/*.gif",
                        "/swagger-resources/**",
                        "/v2/**",
                        "/**/*.ttf"
                );
        web.ignoring().antMatchers("/v2/api-docs",
                "/swagger-resources/configuration/ui",
                "/swagger-resources",
                "/swagger-resources/configuration/security",
                "/swagger-ui.html"
        );
    }
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        /**
         * AuthenticationManager有一个AuthenticationProvider列表，将Authentication委托给列表中的AuthenticationProvider处理认证请求；
         AuthenticationProvider依次对 Authentication 进行认证处理
         //所以会触发CustomAuthenticationProvider的认证
         */
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        http
                .authorizeRequests()
                .mvcMatchers("/favicon.ico", "/signIn", "/signUp", "/security_check", "/404", "/captcha/**", "/user/me").permitAll()
                .mvcMatchers("/oauth/signUp").permitAll()
                //.mvcMatchers("/management/**").hasAnyAuthority(RoleEnum.ROLE_SUPER.name())
               // .anyRequest().access("@rbacauthorityservice.hasPermission(request,authentication)")
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/signIn?out")
                .and()
                .formLogin()
                .authenticationDetailsSource(authenticationDetailsSource) //重点//https://www.cnblogs.com/phoenix-smile/p/5666686.html
                //指向一个AuthenticationFailureHandler用于处理失败的认证请求
                .failureHandler(customAuthenticationFailureHandler)
                //指向一个AuthenticationSuccessHandler用于处理认证成功的请求,不能和default-target-url还有always-use-default-target同时使用
                .successHandler(customAuthenticationSuccessHandler)
                //security_check这个地址可以自定义，登录请求拦截的url,也就是form表单提交时指定的action
                .loginPage("/signIn").loginProcessingUrl("/security_check").permitAll();

        http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
    }




}
